use volo_grpc;

use volo_gen::wmplatform3;

use crate::{
    common,
    tables::{attend::TbAttend, device::TbDevice, netpoint::TbNetPoint},
};

impl From<&TbDevice> for wmplatform3::Device {
    fn from(arg: &TbDevice) -> Self {
        wmplatform3::Device {
            id: arg.id.clone().into(),
            appid: arg.appid.clone().unwrap_or_default().into(),
            device_id: arg.device_id.clone().unwrap_or_default().into(),
            sn: arg.sn.clone().unwrap_or_default().into(),
            ip: arg.ip.clone().unwrap_or_default().into(),
            mac: arg.mac.clone().unwrap_or_default().into(),
            enabled: arg.enabled.unwrap_or_default(),
            status: arg.status.unwrap_or_default(),
            custom_data: arg.custom_data.clone().unwrap_or_default().into(),
        }
    }
}

impl From<wmplatform3::Device> for TbDevice {
    fn from(arg: wmplatform3::Device) -> Self {
        Self {
            id: arg.id.into(),
            appid: Some(arg.appid.into()),
            device_id: Some(arg.device_id.into()),
            sn: Some(arg.sn.into()),
            ip: Some(arg.ip.into()),
            mac: Some(arg.mac.into()),
            enabled: Some(arg.enabled),
            status: Some(arg.status),
            custom_data: Some(arg.custom_data.into()),
        }
    }
}

impl From<wmplatform3::NetPoint> for TbNetPoint {
    fn from(arg: wmplatform3::NetPoint) -> Self {
        Self {
            id: arg.id.into(),
            appid: Some(arg.appid.into()),
            device_id: Some(arg.device_id.into()),
            ip: Some(arg.ip.into()),
            mac: Some(arg.mac.into()),
            name: Some(arg.name.into()),
            last_time: Some(chrono::Utc::now().timestamp()),
            enabled: Some(arg.enabled),
        }
    }
}

impl From<wmplatform3::Attend> for TbAttend {
    fn from(value: wmplatform3::Attend) -> Self {
        Self {
            appid: Some(value.appid.into()),
            attend_type: Some(value.r#type),
            finger_loc: Some(value.finger_loc),
            id: Some(value.id),
            net_point_id: Some(value.net_point_id),
            ip: Some(value.ip.into()),
            username: Some(value.username.into()),
            time: Some(value.time),
        }
    }
}

pub struct S;

impl wmplatform3::VerifyService for S {
    async fn query(
        &self,
        _req: volo_grpc::Request<wmplatform3::QueryReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::QueryRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn get_finger(
        &self,
        _req: volo_grpc::Request<wmplatform3::GetFingerReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::GetFingerRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn update(
        &self,
        _req: volo_grpc::Request<wmplatform3::UpdateReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::UpdateRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn verify(
        &self,
        _req: volo_grpc::Request<wmplatform3::VerifyReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::VerifyRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn identify(
        &self,
        _req: volo_grpc::Request<wmplatform3::IdentifyReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::IdentifyRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn delete_user(
        &self,
        _req: volo_grpc::Request<wmplatform3::DeleteUserReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::DeleteUserRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn get_phone_code(
        &self,
        _req: volo_grpc::Request<wmplatform3::GetPhoneCodeReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::GetPhoneCodeRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn phone_verify(
        &self,
        _req: volo_grpc::Request<wmplatform3::PhoneVerifyReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::PhoneVerifyRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn get_extend_data_by_token(
        &self,
        _req: volo_grpc::Request<wmplatform3::GetExtendDataByTokenReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::GetExtendDataByTokenRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn set_extend_data_by_token(
        &self,
        _req: volo_grpc::Request<wmplatform3::SetExtendDataByTokenReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::SetExtendDataByTokenRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn pwd_update(
        &self,
        _req: volo_grpc::Request<wmplatform3::PwdUpdateReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::PwdUpdateRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn pwd_verify(
        &self,
        _req: volo_grpc::Request<wmplatform3::PwdVerifyReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::PwdVerifyRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn token_check(
        &self,
        _req: volo_grpc::Request<wmplatform3::TokenCheckReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::TokenCheckRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn query_app_log(
        &self,
        _req: volo_grpc::Request<wmplatform3::QueryAppLogReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::QueryAppLogRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn save_app_log(
        &self,
        _req: volo_grpc::Request<wmplatform3::SaveAppLogReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::SaveAppLogRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn delete_app_log(
        &self,
        _req: volo_grpc::Request<wmplatform3::DeleteAppLogReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::DeleteAppLogRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn get_user_count(
        &self,
        _req: volo_grpc::Request<wmplatform3::GetUserCountReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::GetUserCountRsp>, volo_grpc::Status> {
        Ok(volo_grpc::Response::new(Default::default()))
    }

    async fn query_device(
        &self,
        req: volo_grpc::Request<wmplatform3::QueryDeviceReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::QueryDeviceRsp>, volo_grpc::Status> {
        let req = req.into_inner();
        let mut rsp = wmplatform3::QueryDeviceRsp::default();

        Ok(volo_grpc::Response::new(
            match TbDevice::query_devices(&req.appid, &req.device_ids).await {
                Ok(devices) => {
                    rsp.ret = common::Ret::Success.to_u32();
                    rsp.devices = devices.iter().map(wmplatform3::Device::from).collect();
                    rsp
                }
                Err(_) => {
                    rsp.ret = common::Ret::Fail.to_u32();
                    rsp
                }
            },
        ))
    }

    async fn save_device(
        &self,
        req: volo_grpc::Request<wmplatform3::SaveDeviceReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::SaveDeviceRsp>, volo_grpc::Status> {
        let req = req.into_inner();
        if req.devices.is_empty() {
            return Err(volo_grpc::Status::invalid_argument("must have one device"));
        }
        let device = &req.devices[0];

        let mut rsp = wmplatform3::SaveDeviceRsp::default();
        Ok(volo_grpc::Response::new(
            match TbDevice::insert_device(&device.to_owned().into()).await {
                Ok(_) => {
                    rsp.ret = common::Ret::Success.to_u32();
                    rsp
                }
                Err(_) => {
                    rsp.ret = common::Ret::Fail.to_u32();
                    rsp
                }
            },
        ))
    }

    async fn delete_device(
        &self,
        req: volo_grpc::Request<wmplatform3::DeleteDeviceReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::DeleteDeviceRsp>, volo_grpc::Status> {
        let req = req.into_inner();

        let mut rsp = wmplatform3::DeleteDeviceRsp::default();
        Ok(volo_grpc::Response::new(
            match TbDevice::delete_devices_by_appid_and_deviceids(&req.appid, &req.device_ids).await
            {
                Ok(_) => {
                    rsp.ret = common::Ret::Success.to_u32();
                    rsp
                }
                Err(_) => {
                    rsp.ret = common::Ret::Fail.to_u32();
                    rsp
                }
            },
        ))
    }

    async fn net_point_init(
        &self,
        req: volo_grpc::Request<wmplatform3::NetPointInitReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::NetPointInitRsp>, volo_grpc::Status> {
        let req = req.into_inner();
        if req.np.is_none() {
            return Err(volo_grpc::Status::invalid_argument("must have netpoint"));
        }
        let np = req.np.unwrap();
        let query_result =
            TbNetPoint::query_netpoint_by_appid_and_deviceid(&np.appid, &np.device_id).await;
        if let Ok(Some(np)) = query_result {
            if np.enabled == Some(1) {
                return Ok(volo_grpc::Response::new(wmplatform3::NetPointInitRsp {
                    ret: common::Ret::Success.to_u32(),
                    msg: "设备正常".into(),
                }));
            }

            return Ok(volo_grpc::Response::new(wmplatform3::NetPointInitRsp {
                ret: common::Ret::DeviceDisabled.to_u32(),
                msg: "设备未启用".into(),
            }));
        }

        let mut rsp = wmplatform3::NetPointInitRsp::default();
        Ok(volo_grpc::Response::new(
            match TbNetPoint::insert_netpoint(&np.into()).await {
                Ok(_) => {
                    rsp.ret = common::Ret::Success.to_u32();
                    rsp.msg = "设备未启用".into();
                    rsp
                }
                Err(_) => {
                    rsp.ret = common::Ret::Fail.to_u32();
                    rsp.msg = "系统错误, 请联系管理员".into();
                    rsp
                }
            },
        ))
    }

    async fn net_point_attend(
        &self,
        req: volo_grpc::Request<wmplatform3::NetPointAttendReq>,
    ) -> Result<volo_grpc::Response<wmplatform3::NetPointAttendRsp>, volo_grpc::Status> {
        let req = req.into_inner();
        if req.at.is_none() {
            return Err(volo_grpc::Status::invalid_argument("must have attend"));
        }
        let at = &mut req.at.unwrap();
        let query_result =
            TbNetPoint::query_netpoint_by_appid_and_deviceid(&at.appid, &req.device_id).await;
        if query_result.is_err() {
            return Ok(volo_grpc::Response::new(
                wmplatform3::NetPointAttendRsp::default(),
            ));
        }
        let np = query_result.unwrap();
        if np.is_none() {
            return Ok(volo_grpc::Response::new(
                wmplatform3::NetPointAttendRsp::default(),
            ));
        }
        let np = np.unwrap();
        if np.enabled == Some(0) {
            return Ok(volo_grpc::Response::new(
                wmplatform3::NetPointAttendRsp::default(),
            ));
        }
        at.net_point_id = np.id.unwrap();
        let _ = TbAttend::insert_attend(&at.to_owned().into()).await;
        Ok(volo_grpc::Response::new(
            wmplatform3::NetPointAttendRsp::default(),
        ))
    }
}
